//
// Created by fanghr on 17-12-25.
//

#include "session.h"

session::session(boost::asio::io_service &io_service) : socket_(io_service) {
}

session::~session() {
    BOOST_LOG_TRIVIAL(info)<<"Session exit";
    stop();
}

boost::asio::ip::tcp::socket &session::socket() {
    return socket_;
}

void session::start() {
    BOOST_LOG_TRIVIAL(info)<<"Session start at:"<<socket_.remote_endpoint().address().to_string()<<":"<<socket_.remote_endpoint().port()<<".";
    async_read_buf();
}

void session::stop() {
    socket_.close();
}

void session::handle_request(boost::asio::streambuf &buf, boost::system::error_code ec) {
    try {
        uint32_t size=callback(buf);
        async_write_buf(buf,size);
    }
    catch (boost::archive::archive_exception){
        delete this;
        return;
    }
}


void session::async_read_buf() {
    boost::asio::async_read(socket_, boost::asio::buffer(&size, sizeof(uint32_t)),
                            boost::asio::transfer_exactly(sizeof(uint32_t)),
                            boost::bind(&session::handle_read_size, this,
                                        boost::asio::placeholders::error));
}

void session::handle_read_size(boost::system::error_code ec) {
    boost::asio::async_read(socket_, buf,
                            boost::asio::transfer_exactly(size),
                            boost::bind(&session::handle_request, this, boost::ref(buf),
                                        boost::asio::placeholders::error));
}

void session::async_write_buf(boost::asio::streambuf &buf, uint32_t size) {
    boost::asio::async_write(socket_, boost::asio::buffer(&size, sizeof(uint32_t)),
                             boost::asio::transfer_exactly(sizeof(uint32_t)),
                             boost::bind(&session::handle_write_size, this, boost::ref(buf),
                                         boost::asio::placeholders::error));
}

void session::handle_write_size(boost::asio::streambuf &buf, boost::system::error_code ec) {
    boost::asio::async_write(socket_, buf,
                             boost::asio::transfer_exactly(buf.size()),
                             boost::bind(&session::write_cb, this, boost::asio::placeholders::error));
}

void session::write_cb(boost::system::error_code ec) {
    if (ec)delete this;
    else async_read_buf();
}

void session::set_callback(session::callback_t cb) {
    this->callback = cb;
}
